#pragma once

// Disable warnings about invalid XML
#pragma warning(disable:4635)
#include <Awesomium/RenderBuffer.h>
#pragma warning(default:4635)

using namespace System;
using namespace System::Drawing;

namespace AwesomiumDotNet
{
	/// <summary>
	/// The RenderBuffer class represents a 32-bit pixel buffer. The pixel format
    /// is 4 BPP (bytes per pixel) with BGRA (Blue, Green, Red, Alpha) byte ordering.
	/// </summary>
	public ref class RenderBuffer
	{
	internal:
		Awesomium::RenderBuffer* _buffer;
		bool readOnly;

		RenderBuffer(const Awesomium::RenderBuffer* buffer);
		RenderBuffer(Awesomium::RenderBuffer* buffer);

	public:
		/// <summary>
		/// Create a new RenderBuffer with a specified width and height.
		/// </summary>
		RenderBuffer(int width, int height);

		/// <summary>
		/// Create a new RenderBuffer to wrap around a specified pixel buffer.
		/// </summary>
		RenderBuffer(IntPtr buffer, int width, int height, int rowSpan, bool autoDeleteBuffer);

		/// <summary>
		/// Create a new RenderBuffer to wrap around a specified pixel buffer.
		/// </summary>
		RenderBuffer(IntPtr buffer, int width, int height, int rowSpan);

		/// <summary>
		/// Copy from a specified source buffer with certain dimensions to a
	    /// specific offset in our buffer.
		/// </summary>
		void CopyArea(RenderBuffer^ sourceBuffer, System::Drawing::Rectangle^ sourceRect, System::Drawing::Rectangle^ destinationRect);
		
		/// <summary>
		/// Copy from a specified source buffer with certain dimensions
		/// </summary>
		void CopyArea(IntPtr sourceBuffer, int sourceRowSpan, System::Drawing::Rectangle^ sourceRect, bool forceOpaque);
		
		/// <summary>
		/// Copy from a specified source buffer with certain dimensions
		/// </summary>
		void CopyArea(IntPtr sourceBuffer, int sourceRowSpan, System::Drawing::Rectangle^ sourceRect);

		/// <summary>
		/// Copy from a specified source buffer (assumed to have the same dimensions)
		/// </summary>
		void CopyFrom(IntPtr sourceBuffer, int sourceRowSpan);

		/// <summary>
		/// Copy this buffer to a specified destination buffer.
		/// </summary>
		/// <param name="destinationBuffer">
		/// The destination buffer (should have same dimensions)
		/// </param>
		/// <param name="destinationDepth">
		/// The depth (either 3 BPP or 4 BPP)
		/// </param>
		/// <param name="convertToRgba">
		/// Whether or not to convert to RGBA format.
		/// </param>
		void CopyTo(IntPtr destinationBuffer, int destinationRowSpan, int destinationDepth, bool convertToRgba);

		/// <summary>
		/// Get the alpha value at a certain point (origin is top-left). This is
		/// useful for alpha-picking.
		/// </summary>
		/// <param name="x">
		/// The x-value of the point.
		/// </param>
		/// <param name="y">
		/// The y-value of the point.
		/// </param>
		/// <returns>
		/// Returns the alpha value at a certain point (255 is comppletely
		/// opaque, 0 is completely transparent).
		/// </returns>
		unsigned char GetAlphaAtPoint(int x, int y);

		/// <summary>
		/// Re-allocate the pixel buffer to be of the specified dimensions
		/// </summary>
		void Reserve(int width, int height);

		/// <summary>
		/// Scroll the specified area by a relative amount of pixels.
		/// </summary>
		void ScrollArea(int dx, int dy, System::Drawing::Rectangle^ clipRect);

		/// <summary>
		/// Save this buffer to a PNG image.
		/// </summary>
		/// <param name="filePath">
		/// The path to the file that will be written.
		/// </param>
		/// <param name="preserveTransparency">
		/// Whether or not transparency (alpha) values should be preserved.
		/// </param>
		/// <returns>
		/// Whether or not the image was successfully saved.
		/// </returns>
		bool SaveToPng(String^ filePath, bool preserveTransparency);

		/// <summary>
		/// Save this buffer to a PNG image.
		/// </summary>
		/// <param name="filePath">
		/// The path to the file that will be written.
		/// </param>
		/// <returns>
		/// Whether or not the image was successfully saved.
		/// </returns>
		bool SaveToPng(String^ filePath);

		/// <summary>
		/// Save this buffer to a JPEG image.
		/// </summary>
		/// <param name="filePath">
		/// The path to the file that will be written.
		/// </param>
		/// <param name="quality">
		/// The compression quality to use, the valid range is 0 to 100, with 100 being the highest.
		/// </param>
		/// <returns>
		/// Whether or not the image was successfully saved.
		/// </returns>
		bool SaveToJpeg(String^ filePath, int quality);

		/// <summary>
		/// Save this buffer to a JPEG image.
		/// </summary>
		/// <param name="filePath">
		/// The path to the file that will be written.
		/// </param>
		/// <returns>
		/// Whether or not the image was successfully saved.
		/// </returns>
		bool SaveToJpeg(String^ filePath);

		array<System::Byte>^ Copy(int destinationRowSpan, int destinationDepth, bool convertToRGBA);
		void CopyTo(array<System::Byte>^ destinationBuffer, int destinationRowSpan, int destinationDepth, bool convertToRGBA);
		Bitmap^ ToBitmap(int destinationRowSpan, int destinationDepth);
		void ToBitmap(Bitmap^ bitmap);

		/// <summary>
		/// The raw block of pixel data, BGRA format
		/// </summary>
		property IntPtr Buffer
		{
			IntPtr get();
			void set(IntPtr value);
		}

		/// <summary>
		/// The width, in pixels
		/// </summary>
		property int Width
		{
			int get();
			void set(int value);
		}

		/// <summary>
		/// The height, in pixels
		/// </summary>
		property int Height
		{
			int get();
			void set(int value);
		}

		/// <summary>
		/// The number of bytes per row (is usually width * 4 but can be different)
		/// </summary>
		property int RowSpan
		{
			int get();
			void set(int value);
		}

		/// <summary>
		/// Whether or not 'buffer' will be de-allocated upon destruction.
		/// </summary>
		property bool OwnsBuffer
		{
			bool get();
			void set(bool value);
		}

		property bool ReadOnly
		{
			bool get();
		}

	internal:
		property const Awesomium::RenderBuffer* UnmanagedPointer {
			const Awesomium::RenderBuffer* get();
		}
	};
};